package com.qdd.freight.handler;

import com.qdd.freight.entity.Datas;
import com.qdd.freight.exception.FreightCountFailureException;
import com.qdd.freight.exception.FreightToBeZeroExcption;
import com.qdd.freight.pojo.GoodsShip;
import com.qdd.freight.pojo.Logistics;

import java.util.Map;

/**
 * @ClassName AbstractLogisticsCommomHandler
 * @Description TODO (通用计算逻辑------适用于除德邦物流和整车运输之外的其它物流承运商)
 * @Author Yan
 * @Date 2019/12/26 8:23
 * @Version 1.0
 **/

public abstract class AbstractLogisticsCommonHandler extends AbstractLogisticsHandler {

    abstract protected String getShipFieldNameFromInstance();

    @Override
    abstract public Datas realHandle(GoodsShip goodsShip, Integer shipId, Integer modeId, Integer goodsId, Integer entId,
                                     Integer quantity, Integer company, String consignee, Double boxVolume, Double singleVolume,
                                     Double boxWeight, Double singleWeight, Integer QTYRate) throws Exception;

    /**
     * 关键属性值，避免使用时再查询数据库中的字段
     *
     * @param shipId       无愧/快递id
     * @param modeId       快运类型
     * @param goodsId      商品id
     * @param entId        仓库id
     * @param quantity     采购数量
     * @param company      企业编号
     * @param consignee    省市区编号
     * @param boxVolume    整箱体积
     * @param singleVolume 单件体积
     * @param boxWeight    整箱重量
     * @param singleWeight 单件重量
     * @param QTYRate      箱规
     * @return
     * @throws Exception
     */
    protected Datas commonFreightCount(Integer shipId, Integer modeId, Integer goodsId, Integer entId, Integer quantity, Integer company,
                                       String consignee, Double boxVolume, Double singleVolume, Double boxWeight,
                                       Double singleWeight, Integer QTYRate) throws Exception {
        System.out.println("不在禁运列表中，开始计算逻辑。。。。。。。。");
        /*
           1.获取物流对象对象
         */
        //1.1 根据物流编号从数据库中获取对应的物流对象
        Logistics logistics = getLogistics(shipId);
        //获取级别标志位
        Integer ifLevel = logistics.getIfLevel();
        //1.2调用父类方法获取可用的计价方式参数
        Map<String, Object> params = getAvailableParams(logistics, shipId, consignee);
        //获取默认价格
        Double defaultPrice = (Double) params.get("defaultPrice");
        //1.3如果不存在级别设置,就返回默认值
        if (ifLevel == 0) {
            return packageDatas(modeId, goodsId, entId, quantity, defaultPrice);
        }
        //判断是否存在级别字符串
        String levelRule = (String) params.get("levelRule");
        //如果有级别设置,继续获取其它参数
        Double startingPrice = (Double) params.get("startingPrice");
        String levelPrice = (String) params.get("levelPrice");

        /*
            2.开始计算
         */
        //2.1获取计价方式
        Integer countType = logistics.getCountType();
        Double freight;
        //2.2调用不同的计价方法,执行计算逻辑
        switch (countType) {
            case 0:
                //计件数方式计算
                System.out.println("===========计件方式计算=============");
                freight = countByNum(ifLevel, quantity, defaultPrice, startingPrice, levelRule, levelPrice);
                break;
            case 1:
                //计重量方式计算
                //todo 和体积使用同样的方式，只是入参不同，前提是体积和重量都是double类型！！！
                System.out.println("===========计体积方式计算=============");
                freight = countByWeight(ifLevel, quantity, defaultPrice, startingPrice, levelRule, levelPrice,
                        boxWeight, singleWeight, QTYRate);
                break;
            case 2:
                //计体积方式计算
                System.out.println("===========计重方式计算=============");
                freight = countByVolume(ifLevel, quantity, defaultPrice, startingPrice, levelRule, levelPrice,
                        boxVolume, singleVolume, QTYRate);
                break;
            default: //默认计件
                freight = countByNum(ifLevel, quantity, defaultPrice, startingPrice, levelRule, levelPrice);
        }
        System.out.println("当前采购数量为：" + quantity + "，运费为：" + freight);

        if (freight == null) {
            throw new FreightCountFailureException("服务器开小差了，再试一次....");
        }
        if (freight.equals(Double.valueOf(0))) {
            throw new FreightToBeZeroExcption("运费计算结果为0！");
        }

        //调用直接父类方法封装返回结果
        return packageDatas(modeId, goodsId, entId, quantity, freight);
//      //由前端处理，后台不再判断
//        //判断是否是送货上门
//        switch (DELIVERY_TYPE) {
//            case 2:
//                datas.setIf_baoyou(1);
//                break;
//            default:
//                datas.setIf_baoyou(0);
//        }
    }

    /**
     * 核心方法: 计件方式计算
     *
     * @param ifLevel
     * @param defaultPrice
     * @param startingPrice
     * @param levelRule
     * @param levelPrice
     * @return
     */
    private Double countByNum(Integer ifLevel, Integer quantity, Double defaultPrice, Double startingPrice,
                              String levelRule, String levelPrice) {
        //无阶梯设置--直接返回默认价格
        if (ifLevel == null || ifLevel == 0) {
            return defaultPrice;
        }
        //获取采购数量所在的级别
        Integer index = getLevelByComparand(Double.valueOf(quantity), levelRule);
        //获取该级别下对应的价格
        return getFreightByLevel(index, defaultPrice, startingPrice, levelRule, levelPrice);

    }

    /**
     * 核心方法: 计重量方式计算
     *
     * @param ifLevel
     * @param quantity
     * @param defaultPrice
     * @param startingPrice
     * @param levelRule
     * @param levelPrice
     * @param boxWeight
     * @param singleWeight
     * @param QTYRate
     * @return
     */
    private Double countByWeight(Integer ifLevel, Integer quantity, Double defaultPrice, Double startingPrice,
                                 String levelRule, String levelPrice, Double boxWeight, Double singleWeight, Integer QTYRate) {
        //无阶梯设置--直接返回默认价格
        if (ifLevel == null || ifLevel == 0) {
            System.out.println("返回计重默认价格：" + defaultPrice);
            return defaultPrice;
        }
        //调用父类方法获取总重量
        Double totalWeight = getTotalWeightOrVolume(quantity, boxWeight, singleWeight, QTYRate);
        //获取总重量所在的等级
        Integer index = getLevelByComparand(totalWeight, levelRule);
        //获取所在等级所对应的价格
        return getFreightByLevel(index, defaultPrice, startingPrice, levelRule, levelPrice);
    }


    /**
     * 核心方法: 计体积方式计算
     *
     * @param defaultPrice
     * @param startingPrice
     * @param levelRule
     * @param levelPrice
     * @return
     */
    private Double countByVolume(Integer ifLevel, Integer quantity, Double defaultPrice, Double startingPrice,
                                 String levelRule, String levelPrice, Double boxVolume, Double singleVolume, Integer QTYRate) {
        //直接调用计重方式下的算法
        return countByWeight(ifLevel, quantity, defaultPrice, startingPrice, levelRule, levelPrice, boxVolume, singleVolume, QTYRate);
    }
}
